<template>
  <div class="container">
    <div>
      <el-steps :active="step" align-center>
        <el-step title="上传左右眼底图片" icon="el-icon-picture"></el-step>
        <el-step title="点击'开始识别'按钮" icon="el-icon-aim"></el-step>
        <el-step title="生成图片描述" icon="el-icon-connection"></el-step>
        <el-step title="查看诊断结果" icon="el-icon-data-line"></el-step>
      </el-steps>
    </div>
    <div class="main-box">
      <div class="upper-area">
        <div class="image-area">
          <div class="left-upload">
            <div class="pic-upload">
              <div class="text-tip">
                <img src="../assets/image/left_eye.png" alt="" class="tip-icon"/>
                <div class="tip-text">请上传左眼眼底图片</div>
              </div>
              <el-upload
                  drag
                  action="/api/model/uploadImage?sign=left"
                  :limit="1"
                  ref="leftFundusUpload"
                  :on-exceed="handleExceed"
                  :on-remove="handleRemove"
                  :on-progress="handleProgress"
                  :on-success="handleSuccess"
                  :on-error="handleError"
                  accept=".jpg,.jpeg,.png"
                  :auto-upload="true"
              >
                <i class="el-icon-upload"></i>
                <div class="el-upload__text">将左眼眼底图像文件拖到此处，或<em>点击上传</em></div>
                <div class="el-upload__tip" slot="tip">tips: 只能上传jpg/png文件，且不超过500kb</div>
              </el-upload>
            </div>

            <img src="../assets/image/right_arrow.png" alt="" class="arrow-img"/>

            <div class="pic-enhance">
              <div class="text-tip">
                <img src="../assets/image/image_proc.png" alt="" class="tip-icon"/>
                <div class="tip-text">图片预处理结果如下</div>
              </div>
              <div class="enhance-pic-inner">
                <div class="without-img" v-if="leftEnhanceImg === ''">
                  <img src="../assets/image/light.png" alt="" class="enhance-icon"/>
                  <div class="enhance-tip">DCENet图像增强</div>
                </div>
                <div class="with-img" v-else>
                  <img :src="leftEnhanceImg" alt="" style="width: 100%;height: 100%;object-fit: cover;"/>
                </div>
              </div>
              <div>
                <el-link type="info" :underline="false">需要下载增强后的图片?</el-link>
                <el-link type="primary" :underline="false" @click="saveEnhanceImg(0)">点击这里</el-link>
              </div>
            </div>

          </div>

          <div class="right-upload">
            <div class="pic-upload">
              <div class="text-tip">
                <img src="../assets/image/right_eye.png" alt="" class="tip-icon"/>
                <div class="tip-text">请上传右眼眼底图片</div>
              </div>
              <el-upload
                  drag
                  action="/api/model/uploadImage?sign=right"
                  :limit="1"
                  ref="rightFundusUpload"
                  :on-exceed="handleExceed"
                  :on-remove="handleRemove"
                  :on-progress="handleProgress"
                  :on-success="handleSuccess"
                  :on-error="handleError"
                  accept=".jpg,.jpeg,.png"
                  :auto-upload="true"
              >
                <i class="el-icon-upload"></i>
                <div class="el-upload__text">将右眼眼底图像文件拖到此处，或<em>点击上传</em></div>
                <div class="el-upload__tip" slot="tip">tips: 只能上传jpg/png文件，且不超过500kb</div>
              </el-upload>
            </div>

            <img src="../assets/image/right_arrow.png" alt="" class="arrow-img"/>

            <div class="pic-enhance">
              <div class="text-tip">
                <img src="../assets/image/image_proc.png" alt="" class="tip-icon"/>
                <div class="tip-text">图片预处理结果如下</div>
              </div>
              <div class="enhance-pic-inner">
                <div class="without-img" v-if="rightEnhanceImg === ''">
                  <img src="../assets/image/light.png" alt="" class="enhance-icon"/>
                  <div class="enhance-tip">DCENet图像增强</div>
                </div>
                <div class="with-img" v-else>
                  <img :src="rightEnhanceImg" alt="" style="width: 100%;height: 100%;object-fit: cover;"/>
                </div>
              </div>
              <div class="enhance-download">
                <el-link type="info" :underline="false">需要下载增强后的图片?</el-link>
                <el-link type="primary" :underline="false" @click="saveEnhanceImg(1)">点击这里</el-link>
              </div>
            </div>
          </div>
        </div>
        <div class="result-area">
          <div class="merge-arrow">
            <img src="../assets/image/merge.png" alt="" style="width: 100%;height: 100%"/>
          </div>
          <div class="result-info">
            <div class="gram-cam">
              <div class="grad-cam-blank"></div>
              <div class="text-tip">
                <img src="../assets/image/gradCam.png" alt="" class="tip-icon"/>
                <div class="tip-text">模型关注区域（热力图）如下</div>
              </div>
              <div class="grad-cam-img">
                <div class="left-grad-cam">
                  <div class="without-grad-img" v-if="leftGradCam === ''">
                    <img src="../assets/image/heatmap.png" alt="" class="grad-cam-icon"/>
                    <div class="grad-cam-tip">WCG-VMamba左眼热力图</div>
                  </div>
                  <div class="with-grad-img" v-else>
                    <img :src="leftGradCam" alt="" style="width: 100%;height: 100%;object-fit: cover;"/>
                  </div>
                </div>
                <div class="right-grad-cam">
                  <div class="without-grad-img" v-if="rightGradCam === ''">
                    <img src="../assets/image/heatmap.png" alt="" class="grad-cam-icon"/>
                    <div class="grad-cam-tip">WCG-VMamba右眼热力图</div>
                  </div>
                  <div class="with-grad-img" v-else>
                    <img :src="rightGradCam" alt="" style="width: 100%;height: 100%;object-fit: cover;"/>
                  </div>
                </div>
              </div>
            </div>
            <div class="divider">
              <el-divider><i class="el-icon-sort"></i></el-divider>
            </div>
            <div class="probability-list">
              <div class="text-tip">
                <img src="../assets/image/prob.png" alt="" class="tip-icon"/>
                <div class="tip-text">患者患病情况如下
                  <el-link type="primary" :underline="false" @click="showAllResult">(查看全部预测结果及疾病风险评分)
                  </el-link>
                </div>
                <el-link type="info" :underline="false" @click="clickShowSolution" class="showSolution">
                  (查看疾病成因及就诊建议)
                </el-link>
              </div>
              <div class="result-echarts"></div>
            </div>
          </div>
        </div>
      </div>

      <div class="submit-group">
        <div class="submit-btn">
          <el-button type="primary" round @click="startDiagnosis">开始识别<i class="el-icon-check"></i></el-button>
          <el-dropdown style="margin-left: 10px" v-if="showExportButton === true">
            <el-button round type="success">
              一键导出<i class="el-icon-arrow-down el-icon--right"></i>
            </el-button>
            <el-dropdown-menu slot="dropdown">
              <el-dropdown-item @click.native="exportDiagnosisResult">.docx文件</el-dropdown-item>
              <el-dropdown-item @click.native="exportPDFDiagnosisResult">.pdf文件</el-dropdown-item>
            </el-dropdown-menu>
          </el-dropdown>
        </div>
        <div class="auto-diagnosis-tip">手动上传太麻烦？
          <el-upload
              action="https://yiyuy.mynatapp.cc/data/parsePdf"
              accept=".pdf"
              :show-file-list="false"
              :limit="1"
              ref="autoFileUpload"
              :on-success="handleAutoDiagnosisSuccess"
              :on-error="handleAutoDiagnosisError"
              :on-progress="handleAutoDiagnosisProgress"
              :on-exceed="handleAutoDiagnosisExceed">
            <div class="click-me">点我上传</div>
          </el-upload>
          符合模板格式的pdf文件一键诊断
          <div class="download-template" @click="downloadPdfTemplate">(下载模板)</div>
        </div>
      </div>

      <!-- 全部疾病预测结果 -->
      <el-drawer
          title="全部预测结果及疾病风险评分"
          :visible.sync="showAllProb"
          direction="rtl"
          size="40%">
        <div class="drawer-box">
          <div class="text-tip">
            <img src="../assets/image/prob.png" alt="" class="tip-icon"/>
            <div class="tip-text">全部预测结果</div>
          </div>
          <el-table
              border
              :data="allProbTable"
              style="width: 100%"
              :row-class-name="tableRowClassName">
            <el-table-column
                prop="abbreviation"
                label="疾病缩写">
            </el-table-column>
            <el-table-column
                prop="disease"
                label="疾病全称">
            </el-table-column>
            <el-table-column
                prop="prob"
                label="预测结果">
            </el-table-column>
          </el-table>
          <div class="text-tip" style="margin-top: 10px">
            <img src="../assets/image/healthyScore.png" alt="" class="tip-icon"/>
            <div class="tip-text">疾病风险评分及疾病严重分级</div>
            <el-tooltip class="item" effect="dark" placement="top">
              <div slot="content">疾病风险评分：范围为0~100，数值越大代表风险越大<br/>疾病严重分级：共6级，0-无风险，20-轻，40-较轻，60-较重，80-重，100-严重
              </div>
              <el-link type="info" :underline="false">(什么是疾病风险评分及疾病严重分级)</el-link>
            </el-tooltip>
          </div>
          <div class="risk-score-echarts"></div>
        </div>
      </el-drawer>

      <!-- 是否同意采集信息 -->
      <el-dialog title="是否同意采集信息" :visible.sync="gatherInformation" width="30%" center>
        <!-- 采集信息表格 -->
        <el-dialog
            width="25%"
            title="完善信息表格"
            :visible.sync="innerGatherInformation"
            append-to-body
            center>

          <el-form ref="form" :model="infoForm" label-width="80px">
            <el-form-item label="年龄">
              <el-input v-model="infoForm.age" placeholder="请填写您的年龄"></el-input>
            </el-form-item>
            <el-form-item label="性别">
              <el-radio-group v-model="infoForm.gender">
                <el-radio label="Male">男性</el-radio>
                <el-radio label="Female">女性</el-radio>
              </el-radio-group>
            </el-form-item>
            <el-form-item label="症状">
              <el-input v-model="infoForm.description" placeholder="请填写疾病在这段时间给您带来的不适" type="textarea"
                        :rows="2"></el-input>
            </el-form-item>
            <el-form-item>
              <el-button type="success" @click="submitInfoForm" size="small">填写完成</el-button>
              <el-button size="small" type="danger" @click="innerGatherInformation = false">取消</el-button>
            </el-form-item>
          </el-form>

        </el-dialog>
        <div class="outer-text">
          我们希望用1~2分钟时间采集您的信息，用于疾病科普及医生查阅参考病例，让更多眼底疾病患者得到救治，您的私密信息将不会涉及填写。
        </div>
        <div slot="footer" class="dialog-footer">
          <el-button @click="gatherInformation = false" size="small">不同意</el-button>
          <el-button type="primary" @click="agreeGatherInformation" size="small">我同意</el-button>
        </div>
      </el-dialog>

      <!-- 疾病成因及就诊建议窗口 -->
      <el-dialog title="疾病成因及就诊建议" :visible.sync="showSolutionDialog" width="30%" center>
        <el-dialog
            width="25%"
            title="相似病例"
            :visible.sync="innerSimilarCase"
            append-to-body
            center>

          <div>
            <h3>患者信息</h3>
            <p>年龄：{{ similarCase.age }}，性别：{{ similarCase.gender === 'Male' ? '女' : '男' }}</p>
            <h3>眼底图像</h3>
            <div>
              <img :src="similarCase.leftFundus" alt="" style="width: 50%;height: 100%">
              <img :src="similarCase.rightFundus" alt="" style="width: 50%;height: 100%">
            </div>
            <h3>患者自述症状</h3>
            <p>{{ similarCase.description }}</p>
          </div>

        </el-dialog>
        <div v-if="suggestionList.length > 0" v-for="(item,index) in suggestionList" :key="index">
          <h2>{{ item.disease }}</h2>
          <h3>疾病成因</h3>
          <p>{{ item.reason }}</p>
          <h3>就诊建议</h3>
          <div v-html="item.advice"></div>
          <h3>相似病例</h3>
          <el-link type="primary" v-for="(item,index) in item.similarList" :key="index" @click="showDetailInfo(item)"
                   style="margin-left: 5px">
            {{ item.age }}岁{{ item.gender === 'Male' ? '女' : '男' }}性患者
          </el-link>
        </div>
        <div v-else>
          <h3>您的眼底很健康，请继续爱护您的眼睛。</h3>
        </div>
        <div slot="footer" class="dialog-footer">
          <el-button type="success" @click="showSolutionDialog = false" size="small">我知道了</el-button>
        </div>
      </el-dialog>

      <!-- 生成pdf报告组件 -->
      <vue-html2pdf
          :show-layout="false"
          :float-layout="true"
          :enable-download="true"
          :preview-modal="false"
          :paginate-elements-by-height="1400"
          filename="眼底疾病识别诊断结果"
          :pdf-quality="2"
          :manual-pagination="true"
          pdf-format="a4"
          pdf-orientation="portrait"
          pdf-content-width="800px"
          ref="html2Pdf"
      >
        <section slot="pdf-content">
          <!-- 这里写要生成PDF的元素 -->
          <section class="pdf-item">
             <span>
                 <div class="wrapper">
                     <div class="header">
                         <div class="header-title">眼底疾病识别诊断结果</div>
                         <p>诊断时间：{{ new Date().toLocaleString() }}</p>
                     </div>
                     <div class="blank"></div>
                     <div class="main">
                       <el-form label-position="left" label-width="auto">
                         <el-form-item label="用户名">
                          <el-tag>{{ nowUser.username }}</el-tag>
                        </el-form-item>
                         <el-form-item label="患者性别">
                           <el-radio-group v-model="infoForm.gender" :disabled="true" size="small">
                              <el-radio-button label="Male"></el-radio-button>
                              <el-radio-button label="Female"></el-radio-button>
                            </el-radio-group>
                         </el-form-item>
                         <el-form-item label="患者年龄">
                           <el-tag>{{ infoForm.age }}</el-tag>
                         </el-form-item>
                         <el-form-item label="眼底图像">
                            <div class="fundus-image">
                              <img :src="leftBase64" alt="" style="width: 50%;height: 100%"/>
                              <img :src="rightBase64" alt="" style="width: 50%;height: 100%"/>
                            </div>
                         </el-form-item>
                         <el-form-item label="识别结果">
                            <el-tag type="success" effect="dark">{{ textResult }}</el-tag>
                         </el-form-item>
                         <el-form-item label="就诊建议">
                            <div v-html="textSuggestion"></div>
                         </el-form-item>
                       </el-form>
                     </div>
                 </div>
             </span>
          </section>
        </section>
      </vue-html2pdf>

    </div>
  </div>
</template>

<script>
import * as echarts from 'echarts';
import {
  enhanceImage,
  getImageDescription,
  getProbList,
  getSingleDescription,
  makeGradCam,
  uploadPDFImageTOAutoDL
} from "@/api/diagnosis";
import axios from "axios";
import {getTopKCase, submitInfo} from "@/api/info";
import {io} from "socket.io-client";

// 生成疾病检测结果
import Docxtemplater from "docxtemplater";
import PizZip from "pizzip";
import {saveAs} from "file-saver";
import ImageModule from 'docxtemplater-image-module-free';

import VueHtml2pdf from "vue-html2pdf";
import {getUserInfo} from "@/api/login";

const animationDuration = 2000
export default {
  name: "SingleDiagnosis",
  data() {
    return {
      // 全局加载组件
      loading: undefined,
      // 文字版本的识别结果和诊断建议 用于pdf生成
      textSuggestion: '',
      textResult: '',
      // 当前用户信息
      nowUser: '',
      // 是否显示下载检测结果的按钮
      showExportButton: false,
      // 是否显示相似病例窗口
      innerSimilarCase: false,
      // 要查看的患者信息
      similarCase: {},
      // 疾病成因及建议
      suggestionList: [],
      idxToDisease: {
        0: '正常',
        1: '糖尿病',
        2: '青光眼',
        3: '白内障',
        4: 'AMD',
        5: '高血压',
        6: '近视',
        7: '其他疾病/异常'
      },
      idxToReason: {
        1: '糖尿病是一种慢性代谢性疾病，其病因尚不完全清楚，但可能与遗传、环境因素、生活方式等因素有关。糖尿病的主要症状包括多尿、多饮、体重下降、视力模糊等。糖尿病的诊断主要依靠血糖检测，包括空腹血糖、随机血糖、糖化血红蛋白等。',
        2: '青光眼是一种常见的眼部疾病，其成因复杂，可能与高度近视、年龄增长、家族遗传、高血压、糖尿病、眼部炎症、眼内肿瘤、眼部手术等密切相关。',
        3: '白内障是一种常见的老年性眼病，其成因主要是由于晶状体透明度下降，导致光线无法正常聚焦在视网膜上，从而引起视力模糊、视力下降等症状。白内障的成因可能与年龄、遗传、眼部损伤、眼部炎症、糖尿病等密切相关。',
        4: 'AMD是一种常见的老年性眼底疾病，其成因复杂，可能与遗传、环境因素、生活方式等因素有关。AMD的主要症状包括视力模糊、视力下降、视野缩小等。',
        5: '高血压是一种常见的慢性疾病，其成因复杂，可能与遗传、环境因素、生活方式等因素有关。高血压的主要症状包括头晕、头痛、恶心、视力模糊等。',
        6: '近视是一种常见的眼部疾病，其成因复杂，可能与遗传、环境因素、生活方式等因素有关。近视的主要症状包括视力模糊、视力下降、视力疲劳等。。',
        7: '成因不明，建议线下就医。'
      },
      idxToAdvice: {
        1: `<h4>基本治疗</h4><p>控制血糖：严格控制血糖水平是关键，需将血糖控制在正常或接近正常水平,</p><p>控制血压：将血压维持在120/80 mmHg以下，可使视网膜出血风险降低41%。推荐选择ARB类降压药（如缬沙坦），这类药物兼具改善视网膜血流的作用</p><p>健康饮食：保持“视网膜友好型”饮食，包含Ω-3脂肪酸（每周3次深海鱼）、叶黄素（每日1个鸡蛋+200g菠菜）和锌元素（每日10g南瓜籽）。</p><p>规律运动：尽量每周进行至少150分钟的适度有氧运动，如走步。</p><h4>就诊医院</h4><p>您可以去最近的眼科医院，以下是治疗糖尿病视网膜病变最好的前3家医院：中山大学中山眼科中心，首都医科大学附属北京同仁医院，复旦大学附属眼耳鼻喉科医院。</p><h4>就诊科室</h4><p>糖尿病视网膜病变主要就诊于眼科，尤其是眼底病专科。</p><h4>推荐医生</h4><p>推荐您可以找以下医生进行治疗：王红主任医师（山东大学齐鲁医院眼科）,田蓓主任医师（北京同仁医院眼底病科）,陈有信主任医师（北京协和医院眼科）。</p>`,
        2: '<h4>基本治疗</h4><p>保持良好的生活习惯：保证充足的睡眠，避免熬夜，保持规律的作息时间</p><p>定期随访：青光眼是一种需要长期管理的疾病，要按医嘱定期随访，终身治疗</p><p>饮食清淡：避免高脂肪、高糖食物，多吃富含维生素的食品，如蔬菜、水果、粗粮等。同时，保持大便通畅，少吃或不吃刺激性食物</p><p>增加维生素和粗纤维摄入：多吃富含维生素A、B、C、E和粗纤维的食物，如猪肝、鱼、肉、粗粮、植物油等</p><h4>就诊医院</h4><p>您可以去到最近的眼科医院，以下是治疗青光眼最好的前3家医院：中山大学中山眼科中心，上海市第一人民医院（北部），上海市五官科医院。</p><h4>就诊科室</h4><p>青光眼患者应前往眼科就诊，部分医院设有专门的青光眼专科或青光眼与视神经疾病学科</p><h4>推荐医生</h4><p>推荐您可以找以下医生进行治疗：张秀兰主任医师教授（中山大学中山眼科中心），王海燕主任医师（上海市第一人民医院），孔祥梅主任医师（上海市五官科医院）。</p>',
        3: '<h4>基本治疗</h4><p>眼部护理：避免长时间暴露在强光下，外出时佩戴防紫外线眼镜。注意眼部卫生，避免用手揉眼睛</p><p>避免强光刺激：外出时可戴太阳镜或宽边帽，减少眩光</p><p>多摄入抗氧化食物：多吃富含维生素C、E和叶黄素的食物，如深色蔬菜、坚果、鱼类、蓝莓、菠菜、胡萝卜等</p><p>补充锌和蛋白质：适量食用富含锌的食物，如青鱼、瘦肉、花生、核桃、牡蛎等。同时，保证足够的蛋白质摄入</p><h4>就诊医院</h4><p>您可以去到最近的眼科医院，以下是治疗白内障最好的前3家医院：中山大学中山眼科中心，北京同仁医院，温州医科大学附属眼视光医院</p><h4>就诊科室</h4><p>白内障患者应前往眼科就诊，部分医院设有专门的白内障专科或白内障与晶状体疾病学科，</p><h4>推荐医生</h4><p>推荐您可以找以下医生进行治疗：季樱红主任医师（上海市五官科医院白内障与晶状体疾病学科），周民稳主任医师（上海市第一人民医院眼科），王海燕主任医师（上海市第一人民医院眼科）。</p>',
        4: '<h4>基本治疗</h4><p>健康饮食：多吃富含抗氧化剂的食物，如深绿色蔬菜（羽衣甘蓝、菠菜）、水果、坚果和鱼类。地中海饮食模式对AMD有益，其特点是高摄入蔬菜、水果、全谷物、豆类、橄榄油和鱼类，低摄入红肉和加工肉类</p><p>控制体重和运动：保持健康体重，定期进行适度运动，如散步、游泳等</p><p>增加抗氧化剂摄入：富含叶黄素和玉米黄质的食物（如菠菜、羽衣甘蓝）、富含维生素C的食物（如柑橘类水果、草莓）、富含维生素E的食物（如坚果、种子）</p><p>摄入ω-3脂肪酸：如鲑鱼、金枪鱼、核桃等，有助于降低晚期AMD风险</p><h4>就诊医院</h4><p>您可以去到最近的眼科医院，同时您可以去到最近的眼科医院，以下是治疗AMD最好的前3家医院：北京同仁医院，厦门大学附属厦门眼科中心，上海市第一人民医院</p><h4>就诊科室</h4><p>AMD患者应前往眼科就诊，尤其是眼底病专科</p><h4>推荐医生</h4><p>推荐您可以找以下医生进行治疗：魏文斌教授（北京同仁医院），黎晓新教授（厦门大学附属厦门眼科中心），肖泽锋主任（武汉市第一医院）。</p>',
        5: '<h4>基本治疗</h4><p>控制血压：遵医嘱按时服药，定期监测血压，保持血压稳定</p><p>适度运动：选择散步、慢跑、游泳、太极拳等中等强度的运动，每周至少150分钟，避免剧烈运动导致血压波动</p><p>低脂饮食：减少动物脂肪摄入，选择植物油如橄榄油、玉米油等，避免油炸食品和高脂肪肉类</p><p>低盐饮食：每日盐摄入量控制在5克以内，避免食用咸菜、腌肉等高盐食品</p><h4>就诊医院</h4><p>您可以去到最近的眼科医院，以下是治疗高血压最好的前3家医院：北京协和医院，武汉大学人民医院，山东大学齐鲁医院</p><h4>就诊科室</h4><p>高血压视网膜病变通常需要到眼科就诊，尤其是眼底病专科。如果病情复杂，可能还需要与心血管内科协作，以更好地控制血压</p><h4>推荐医生</h4><p>推荐您可以找以下医生进行治疗：封康副主任医师（北医三院眼科），王红主任医师（山东大学齐鲁医院眼科），邢怡桥主任医师（武汉大学人民医院眼科中心）</p>',
        6: '<h4>基本治疗</h4><p>用眼习惯：遵循“20-20-20”法则，即每用眼20分钟，休息20秒，远眺20英尺（约6米）的地方。避免长时间近距离用眼，保持适当的阅读距离，确保光线充足</p><p>户外活动：增加户外活动时间，每天至少2-3小时，让眼睛接触自然光线，有助于预防近视</p><p>增加营养摄入：多吃富含维生素A、C、E和Omega-3脂肪酸的食物，如胡萝卜、菠菜、鸡蛋、深海鱼等。这些营养素有助于保护眼睛，增强夜间视力，同时能预防干眼症</p><p>补充钙和锌：钙和锌对眼睛健康很重要，可以通过食用鱼类、豆制品、坚果等食物来补充</p><h4>就诊医院</h4><p>您可以去到最近的眼科医院，以下是治疗近视最好的前3家医院：浙江大学医学院附属第二医院（杭州）,复旦大学附属眼耳鼻喉科医院（上海）,上海市第一人民医院（上海）</p><h4>就诊科室</h4><p>近视患者通常需要前往眼科就诊，部分医院设有专门的视光科或屈光科，专门处理近视、远视、散光等屈光问题</p><h4>推荐医生</h4><p>推荐您可以找以下医生进行治疗：余克明主任医师（中山大学中山眼科中心），翟长斌主任医师（首都医科大学附属北京同仁医院），周行涛主任医师（复旦大学附属眼耳鼻喉科医院）</p>',
        7: '成因不明，建议线下前往最近眼科医院进行就医。'
      },
      idxToAdviceWithoutHTML: {
        1: `基本治疗：控制血糖：严格控制血糖水平是关键，需将血糖控制在正常或接近正常水平,控制血压：将血压维持在120/80 mmHg以下，可使视网膜出血风险降低41%。推荐选择ARB类降压药（如缬沙坦），这类药物兼具改善视网膜血流的作用，健康饮食：保持“视网膜友好型”饮食，包含Ω-3脂肪酸（每周3次深海鱼）、叶黄素（每日1个鸡蛋+200g菠菜）和锌元素（每日10g南瓜籽），规律运动：尽量每周进行至少150分钟的适度有氧运动，如走步。。就诊医院：您可以去最近的眼科医院，以下是治疗糖尿病视网膜病变最好的前3家医院：中山大学中山眼科中心，首都医科大学附属北京同仁医院，复旦大学附属眼耳鼻喉科医院。就诊科室：糖尿病视网膜病变主要就诊于眼科，尤其是眼底病专科。推荐医生：推荐您可以找以下医生进行治疗：王红主任医师（山东大学齐鲁医院眼科）,田蓓主任医师（北京同仁医院眼底病科）,陈有信主任医师（北京协和医院眼科）。`,
        2: '基本治疗：保持良好的生活习惯：保证充足的睡眠，避免熬夜，保持规律的作息时间，定期随访：青光眼是一种需要长期管理的疾病，要按医嘱定期随访，终身治疗，饮食清淡：避免高脂肪、高糖食物，多吃富含维生素的食品，如蔬菜、水果、粗粮等。同时，保持大便通畅，少吃或不吃刺激性食物，增加维生素和粗纤维摄入：多吃富含维生素A、B、C、E和粗纤维的食物，如猪肝、鱼、肉、粗粮、植物油等。就诊医院：您可以去到最近的眼科医院，以下是治疗青光眼最好的前3家医院：中山大学中山眼科中心，上海市第一人民医院（北部），上海市五官科医院。就诊科室：青光眼患者应前往眼科就诊，部分医院设有专门的青光眼专科或青光眼与视神经疾病学科。推荐医生：推荐您可以找以下医生进行治疗：张秀兰主任医师教授（中山大学中山眼科中心），王海燕主任医师（上海市第一人民医院），孔祥梅主任医师（上海市五官科医院）。',
        3: '基本治疗：眼部护理：避免长时间暴露在强光下，外出时佩戴防紫外线眼镜。注意眼部卫生，避免用手揉眼睛，避免强光刺激：外出时可戴太阳镜或宽边帽，减少眩光，多摄入抗氧化食物：多吃富含维生素C、E和叶黄素的食物，如深色蔬菜、坚果、鱼类、蓝莓、菠菜、胡萝卜等，补充锌和蛋白质：适量食用富含锌的食物，如青鱼、瘦肉、花生、核桃、牡蛎等。同时，保证足够的蛋白质摄入。就诊医院。您可以去到最近的眼科医院，以下是治疗白内障最好的前3家医院：中山大学中山眼科中心，北京同仁医院，温州医科大学附属眼视光医院。就诊科室：白内障患者应前往眼科就诊，部分医院设有专门的白内障专科或白内障与晶状体疾病学科。推荐医生：推荐您可以找以下医生进行治疗：季樱红主任医师（上海市五官科医院白内障与晶状体疾病学科），周民稳主任医师（上海市第一人民医院眼科），王海燕主任医师（上海市第一人民医院眼科）。',
        4: '基本治疗：健康饮食：多吃富含抗氧化剂的食物，如深绿色蔬菜（羽衣甘蓝、菠菜）、水果、坚果和鱼类。地中海饮食模式对AMD有益，其特点是高摄入蔬菜、水果、全谷物、豆类、橄榄油和鱼类，低摄入红肉和加工肉类，控制体重和运动：保持健康体重，定期进行适度运动，如散步、游泳等，增加抗氧化剂摄入：富含叶黄素和玉米黄质的食物（如菠菜、羽衣甘蓝）、富含维生素C的食物（如柑橘类水果、草莓）、富含维生素E的食物（如坚果、种子），摄入ω-3脂肪酸：如鲑鱼、金枪鱼、核桃等，有助于降低晚期AMD风险。就诊医院：您可以去到最近的眼科医院，同时您可以去到最近的眼科医院，以下是治疗AMD最好的前3家医院：北京同仁医院，厦门大学附属厦门眼科中心，上海市第一人民医院，就诊科室：AMD患者应前往眼科就诊，尤其是眼底病专科。推荐医生：推荐您可以找以下医生进行治疗：魏文斌教授（北京同仁医院），黎晓新教授（厦门大学附属厦门眼科中心），肖泽锋主任（武汉市第一医院）。',
        5: '基本治疗：控制血压：遵医嘱按时服药，定期监测血压，保持血压稳定，适度运动：选择散步、慢跑、游泳、太极拳等中等强度的运动，每周至少150分钟，避免剧烈运动导致血压波动，低脂饮食：减少动物脂肪摄入，选择植物油如橄榄油、玉米油等，避免油炸食品和高脂肪肉类，低盐饮食：每日盐摄入量控制在5克以内，避免食用咸菜、腌肉等高盐食品。就诊医院：您可以去到最近的眼科医院，以下是治疗高血压最好的前3家医院：北京协和医院，武汉大学人民医院，山东大学齐鲁医院。就诊科室：高血压视网膜病变通常需要到眼科就诊，尤其是眼底病专科。如果病情复杂，可能还需要与心血管内科协作，以更好地控制血压。推荐医生：推荐您可以找以下医生进行治疗：封康副主任医师（北医三院眼科），王红主任医师（山东大学齐鲁医院眼科），邢怡桥主任医师（武汉大学人民医院眼科中心）。',
        6: '基本治疗：用眼习惯：遵循“20-20-20”法则，即每用眼20分钟，休息20秒，远眺20英尺（约6米）的地方。避免长时间近距离用眼，保持适当的阅读距离，确保光线充足，户外活动：增加户外活动时间，每天至少2-3小时，让眼睛接触自然光线，有助于预防近视，增加营养摄入：多吃富含维生素A、C、E和Omega-3脂肪酸的食物，如胡萝卜、菠菜、鸡蛋、深海鱼等。这些营养素有助于保护眼睛，增强夜间视力，同时能预防干眼症，补充钙和锌：钙和锌对眼睛健康很重要，可以通过食用鱼类、豆制品、坚果等食物来补充。就诊医院：您可以去到最近的眼科医院，以下是治疗近视最好的前3家医院：浙江大学医学院附属第二医院（杭州）,复旦大学附属眼耳鼻喉科医院（上海）,上海市第一人民医院（上海）。就诊科室：近视患者通常需要前往眼科就诊，部分医院设有专门的视光科或屈光科，专门处理近视、远视、散光等屈光问题。推荐医生：推荐您可以找以下医生进行治疗：余克明主任医师（中山大学中山眼科中心），翟长斌主任医师（首都医科大学附属北京同仁医院），周行涛主任医师（复旦大学附属眼耳鼻喉科医院）',
        7: '成因不明，建议线下前往最近眼科医院进行就医。'
      },
      idxToAdviceDoctor: {
        1: '<h4>就诊前准备:</h4><p>整理病史资料：简要总结糖尿病病史，包括确诊时间、既往和当前服用的糖尿病治疗药物、最近的平均血糖水平以及最近几次血红蛋白A1C读数（如果知晓）。</p><p>记录症状：详细记录眼部症状，如视力下降、视物模糊、眼前黑影飘动、视野缺损等，以及出现的时间和频率。</p><h4>就诊时沟通:</h4><p>询问病情和预后：了解糖尿病视网膜病变对视力的潜在影响，询问病变的严重程度、是否可逆以及可能的发展趋势，</p><p>探讨治疗方案：与医生讨论可提供的治疗方法，如激光治疗、抗VEGF治疗、玻璃体手术等，并了解每种方法的适应证、疗效、风险和预期效果。</p><h4>就诊后自我管理：</h4><p>严格控制血糖：在内分泌科医生指导下，科学、平稳地控制血糖，避免血糖波动过大。同时，重视血压和血脂的管理，因为这些因素也会影响视网膜病变的进展</p>',
        2: '<h4>就诊前准备:</h4><p>症状记录：详细记录症状出现的时间、频率、持续时间，以及是否与情绪波动、长时间用眼、黑暗环境等有关。</p><p>病史整理：梳理个人和家族的眼部疾病史、全身疾病史（如高血压、糖尿病等）及用药情况。<p>配合检查：眼压测量：是诊断青光眼的重要指标之一，但需注意眼压正常也不能完全排除青光眼。</p><p>前房角检查：通过前房角镜检查前房角的宽窄、开放程度，帮助判断青光眼的类型。</p><h4>明确诊断后治疗：</h4><p>药物治疗：医生可能会根据病情开具降眼压药物，如前列腺素类药物、β受体阻滞剂、碳酸酐酶抑制剂等，严格按照医嘱使用，注意观察药物的疗效和不良反应。</p><p>激光治疗：对于部分青光眼患者，如房角狭窄或闭角型青光眼早期患者，激光虹膜切开术或激光周边虹膜成形术等激光治疗可能有效。</p>',
        3: '<h4>就诊前准备:</h4><p>就诊前准备：观察患者是否有以下症状：视力逐渐模糊,看东西重影、复视,老花眼突然好转等。</p><h4>就诊时准备：</h4><p>可以做以下检查：视力检查，裂隙灯检查，眼压测试，光学断层扫描（OCT）</p><h4>术后护理：</h4><p>遵医嘱使用滴眼液，预防感染，定期复查，观察恢复情况，注意眼部卫生，避免用力揉眼。</p>',
        4: '<h4>就诊前准备:</h4><p>观察患者症状：如果出现视物模糊、视物变形（如直线变弯）、视野中心出现暗点、视力下降等症状，尤其是年龄超过50岁的人群，应尽快前往医院眼科就诊。</p><h4>检查项目：</h4><p>眼底检查：包括眼底照相、光学相干断层扫描（OCT）和OCT血管成像（OCTA），用于评估黄斑区的结构变化</p><p>荧光素眼底血管造影（FFA）：用于诊断新生血管性AMD（nAMD），明确病变范围和类型。</p><h4>明确治疗方案：</h4><p>早至中期AMD：补充营养素：建议补充抗氧化维生素（维生素C、维生素E）、矿物质（锌、铜）、叶黄素和玉米黄质，有助于延缓疾病进展。</p><p>晚期AMD：干性AMD：目前尚无特效药物，可继续补充营养素以延缓地图样萎缩（GA）的进展。预防与随访：定期复查</p>',
        5: '<h4>就诊前准备:</h4><p>观察患者症状：如果出现视力模糊、眼前黑影飘动、视野缺损、突发头痛、恶心等症状，尤其是合并高血压病史的患者，应立即前往医院眼科就诊。</p><h4>检查项目：</h4><p>眼底检查：包括眼底照相、散瞳检查、光学相干断层扫描（OCT）和荧光素眼底血管造影（FFA）等，用于评估视网膜血管和视神经的病变情况。</p><p>血压监测：定期监测血压，评估血压控制情况，了解血压波动对眼底病变的影响，</p><h4>明确治疗方案：</h4><p>控制血压：积极控制血压是关键，普通高血压患者血压应控制在＜140/90 mmHg，合并糖尿病或肾病者应控制在＜130/80 mmHg，</p><p>药物治疗：根据眼底病变情况，可能需要使用降压药、抗VEGF药物（如雷珠单抗）、皮质类固醇等，预防与随访：定期复查</p>',
        6: '<h4>就诊前准备:</h4><p>观察患者症状：如果出现以下症状，尤其是高度近视（≥600度）患者，应尽快前往医院眼科就诊。<h4>检查项目：</h4><p>视力下降：近视度数持续加深，或视力突然下降，视物变形：如视野中出现黑影、闪光感、视物变形（直线变弯）。</p><h4>检查方式：</h4><p>视力检查：评估视力受损程度。</p><p>眼底检查：包括眼底照相、散瞳检查，观察视网膜、脉络膜和视神经的病变情况。</p><p>光学相干断层扫描（OCT）：用于检测视网膜厚度、黄斑区结构变化。</p><h4>明确诊断后的治疗建议：</h4><p>药物治疗：控制近视进展：对于青少年近视患者，可使用低浓度阿托品滴眼液（0.01%）延缓近视加深。</p><p>手术治疗：屈光手术：对于近视度数稳定（2年内度数变化≤50度）且无眼底病变的患者，可考虑激光角膜切削术（如全飞秒、半飞秒）或人工晶状体植入术（如ICL）。</p>',
        7: '成因不明，应从多个角度考虑患者所患疾病。'
      },
      idxToAdviceDoctorWithoutHTML: {
        1: '就诊前准备:整理病史资料：简要总结糖尿病病史，包括确诊时间、既往和当前服用的糖尿病治疗药物、最近的平均血糖水平以及最近几次血红蛋白A1C读数（如果知晓）。记录症状：详细记录眼部症状，如视力下降、视物模糊、眼前黑影飘动、视野缺损等，以及出现的时间和频率。就诊时沟通:询问病情和预后：了解糖尿病视网膜病变对视力的潜在影响，询问病变的严重程度、是否可逆以及可能的发展趋势，探讨治疗方案：与医生讨论可提供的治疗方法，如激光治疗、抗VEGF治疗、玻璃体手术等，并了解每种方法的适应证、疗效、风险和预期效果。就诊后自我管理：严格控制血糖：在内分泌科医生指导下，科学、平稳地控制血糖，避免血糖波动过大。同时，重视血压和血脂的管理，因为这些因素也会影响视网膜病变的进展',
        2: '就诊前准备：症状记录：详细记录症状出现的时间、频率、持续时间，以及是否与情绪波动、长时间用眼、黑暗环境等有关。病史整理：梳理个人和家族的眼部疾病史、全身疾病史（如高血压、糖尿病等）及用药情况。配合检查：眼压测量：是诊断青光眼的重要指标之一，但需注意眼压正常也不能完全排除青光眼。前房角检查：通过前房角镜检查前房角的宽窄、开放程度，帮助判断青光眼的类型。明确诊断后治疗：药物治疗：医生可能会根据病情开具降眼压药物，如前列腺素类药物、β受体阻滞剂、碳酸酐酶抑制剂等，严格按照医嘱使用，注意观察药物的疗效和不良反应。激光治疗：对于部分青光眼患者，如房角狭窄或闭角型青光眼早期患者，激光虹膜切开术或激光周边虹膜成形术等激光治疗可能有效。',
        3: '就诊前准备：观察患者是否有以下症状：视力逐渐模糊,看东西重影、复视,老花眼突然好转等。就诊时准备：可以做以下检查：视力检查，裂隙灯检查，眼压测试，光学断层扫描（OCT），术后护理：遵医嘱使用滴眼液，预防感染，定期复查，观察恢复情况，注意眼部卫生，避免用力揉眼。',
        4: '观察患者症状：如果出现视物模糊、视物变形（如直线变弯）、视野中心出现暗点、视力下降等症状，尤其是年龄超过50岁的人群，应尽快前往医院眼科就诊，检查项目：眼底检查：包括眼底照相、光学相干断层扫描（OCT）和OCT血管成像（OCTA），用于评估黄斑区的结构变化，荧光素眼底血管造影（FFA）：用于诊断新生血管性AMD（nAMD），明确病变范围和类型。治疗方案：早至中期AMD：补充营养素：建议补充抗氧化维生素（维生素C、维生素E）、矿物质（锌、铜）、叶黄素和玉米黄质，有助于延缓疾病进展。晚期AMD：干性AMD：目前尚无特效药物，可继续补充营养素以延缓地图样萎缩（GA）的进展。预防与随访：定期复查',
        5: '观察患者症状：如果出现视力模糊、眼前黑影飘动、视野缺损、突发头痛、恶心等症状，尤其是合并高血压病史的患者，应立即前往医院眼科就诊，检查项目：眼底检查：包括眼底照相、散瞳检查、光学相干断层扫描（OCT）和荧光素眼底血管造影（FFA）等，用于评估视网膜血管和视神经的病变情况，血压监测：定期监测血压，评估血压控制情况，了解血压波动对眼底病变的影响，治疗方案：控制血压：积极控制血压是关键，普通高血压患者血压应控制在＜140/90 mmHg，合并糖尿病或肾病者应控制在＜130/80 mmHg，药物治疗：根据眼底病变情况，可能需要使用降压药、抗VEGF药物（如雷珠单抗）、皮质类固醇等，预防与随访：定期复查',
        6: '观察患者症状：如果出现以下症状，尤其是高度近视（≥600度）患者，应尽快前往医院眼科就诊：视力下降：近视度数持续加深，或视力突然下降，视物变形：如视野中出现黑影、闪光感、视物变形（直线变弯）。检查方式：视力检查：评估视力受损程度。眼底检查：包括眼底照相、散瞳检查，观察视网膜、脉络膜和视神经的病变情况。光学相干断层扫描（OCT）：用于检测视网膜厚度、黄斑区结构变化。明确诊断后的治疗建议：药物治疗：控制近视进展：对于青少年近视患者，可使用低浓度阿托品滴眼液（0.01%）延缓近视加深。手术治疗：屈光手术：对于近视度数稳定（2年内度数变化≤50度）且无眼底病变的患者，可考虑激光角膜切削术（如全飞秒、半飞秒）或人工晶状体植入术（如ICL）。',
        7: '成因不明，应从多个角度考虑患者所患疾病。'
      },
      // 全局socket 用于获得患病风险评分及程度
      socket: null,
      // 大模型评分回答
      answer: '',
      // 上传的左右眼文件
      leftFile: '',
      rightFile: '',
      // 是否显示同意采集信息窗口
      gatherInformation: false,
      innerGatherInformation: false,
      // 风险评估数据
      gaugeData: [
        {
          value: 0,
          name: '当前疾病风险评分',
          title: {
            offsetCenter: ['0%', '-40%']
          },
          detail: {
            valueAnimation: true,
            offsetCenter: ['0%', '-20%']
          }
        },
        {
          value: 0,
          name: '当前疾病严重分级',
          title: {
            offsetCenter: ['0%', '10%']
          },
          detail: {
            valueAnimation: true,
            offsetCenter: ['0%', '30%']
          }
        }
      ],
      // 是否显示疾病成因及就诊建议
      showSolutionDialog: false,
      // 当前进行到了第几步
      step: 0,
      // 柱状图轴内容
      diseaseBarDataX: ['N', 'D', 'G', 'C', 'A', 'H', 'M', 'O'],
      // 柱状图y轴数值
      probData: [0, 1, 0, 0, 0, 1, 0, 0],
      // 全部疾病患病概率
      allProbTable: [
        {
          abbreviation: 'H',
          disease: '高血压',
          prob: '暂无'
        },
        {
          abbreviation: 'D',
          disease: '糖尿病',
          prob: '暂无'
        },
        {
          abbreviation: 'G',
          disease: '青光眼',
          prob: '暂无'
        },
        {
          abbreviation: 'C',
          disease: '白内障',
          prob: '暂无'
        },
        {
          abbreviation: 'A',
          disease: 'AMD',
          prob: '暂无'
        },
        {
          abbreviation: 'M',
          disease: '近视',
          prob: '暂无'
        },
        {
          abbreviation: 'O',
          disease: '其他疾病/异常',
          prob: '暂无'
        },
        {
          abbreviation: 'N',
          disease: '正常',
          prob: '暂无'
        },
      ],
      // 是否显示全部疾病概率
      showAllProb: false,
      // 表示第i种病的背景颜色
      dangerDegree: {},
      // 左右眼睛图片的base64
      leftBase64: '',
      rightBase64: '',
      // 要提交的表单
      form: {
        leftFilename: '',
        rightFilename: '',
        description: ''
      },
      // 采集信息表格
      infoForm: {
        age: '',
        gender: '',
        description: '',
        leftKeyword: '',
        rightKeyword: '',
        result: '',
        username: ''
      },
      // 左右眼眼底图像增强后base64
      leftEnhanceImg: '',
      rightEnhanceImg: '',
      // 左右眼眼底使用Grad-Cam后的热力图
      leftGradCam: '',
      rightGradCam: '',
    }
  },
  beforeDestroy() {
    // 离开时断开Socketio连接
    if (this.socket !== null) {
      console.log('断开连接')
      this.socket.disconnect();
    }
  },
  mounted() {
    this.$nextTick(function () {
      this.drawResultEcharts()
    })
    this.getNowUserInfo()
    this.initSocket();
  },
  components: {
    //注册组件
    VueHtml2pdf
  },
  methods: {
    initSocket() {
      this.socket = io('https://yiyuy.mynatapp.cc/spark', {
        transports: ['websocket']
      })

      this.socket.on('disconnect', (msg) => {
        this.socket.disconnect()
      })

      // 监听服务器那边返回的消息
      this.socket.on('server_response', (message) => {
        if (message.data === '[over]') {
          // 根据逗号分割
          let array = []
          if (this.answer.includes(',')) {
            array = this.answer.split(',')
          }
          if (this.answer.includes('，')) {
            array = this.answer.split('，')
          }
          console.log(array)
          // answer[0] 代表疾病风险评分 answer[1]代表风险等级
          this.gaugeData[0].value = parseInt(array[0])
          this.gaugeData[1].value = parseInt(array[1])
          this.answer = ''
        } else {
          this.answer += message.data;
        }
      })
    },
    getNowUserInfo() {
      getUserInfo().then(res => {
        this.nowUser = res.data;
      })
    },
    // 自助诊断超出文件数量触发
    handleAutoDiagnosisExceed(files, fileList) {
      this.$message.error('最多只能上传一个pdf文件');
    },
    // 自助诊断上传文件时开启全局加载
    handleAutoDiagnosisProgress(event, files, fileList) {
      this.loading = this.$loading({
        lock: true,
        text: '文件上传中',
        spinner: 'el-icon-loading',
        background: 'rgba(0, 0, 0, 0.7)'
      });
    },
    // 自助诊断上传文件成功
    handleAutoDiagnosisSuccess(response, file, fileList) {
      console.log(response)
      let loadingText = '正在解析pdf文件...'
      this.loading.setText(loadingText)
      // 获取解析后的结果
      this.form = response.data.form;

      this.leftBase64 = 'data:image/png;base64,' + response.data.leftBase64
      this.rightBase64 = 'data:image/png;base64,' + response.data.rightBase64
      this.$refs.autoFileUpload.clearFiles()

      let base64Form = {
        "leftBase64": response.data.leftBase64,
        "rightBase64": response.data.rightBase64
      }

      axios.post('/llava/uploadPDFImage', base64Form).then(res => {
        // 调用开始诊断函数
        this.startDiagnosis();
      })
    },
    // 自助诊断上传pdf文件出错
    handleAutoDiagnosisError(err, file, fileList) {
      this.loading.close();
      this.$message.error('pdf文件上传失败');
    },
    // 为表格每个疾病根据概率添加不同颜色
    tableRowClassName({row, rowIndex}) {
      return this.dangerDegree[rowIndex]
    },
    // 超出时调用的函数
    handleExceed(files, fileList) {
      this.$message.error('最多只能上传一张图片')
    },
    // 移除图片时调用的函数
    handleRemove(files, fileList) {
      this.step = 0;
      this.$message.success('图片移除成功')
    },
    // 图片上传中调用的函数
    handleProgress(event, files, fileList) {
      this.$message.warning('文件上传中...')
    },
    // 文件上传成功调用的函数
    handleSuccess(response, file, fileList) {
      this.step = 1
      if (response.data['sign'] === 'left') {
        this.leftFile = file.raw
        this.form.leftFilename = response.data['filename']
        this.leftBase64 = 'data:image/png;base64,' + response.data['64Url']
      } else {
        this.rightFile = file.raw
        this.form.rightFilename = response.data['filename']
        this.rightBase64 = 'data:image/png;base64,' + response.data['64Url']
      }

      // 在WEB上传成功之后 还要上传到AUTODL服务器
      let formData = new FormData()
      formData.append('file', file.raw)
      axios.post('/llava/uploadImage',formData);

      this.$message.success('文件上传成功啦')
    },
    // 文件上传失败
    handleError(err, file, fileList) {
      this.$message.error('文件上传失败')
    },
    drawRiskScoreEcharts() {
      let riskScoreEcharts = echarts.init(document.querySelector('.risk-score-echarts'));
      riskScoreEcharts.setOption({
        series: [
          {
            type: 'gauge',
            startAngle: 90,
            endAngle: -270,
            pointer: {
              show: false
            },
            progress: {
              show: true,
              overlap: false,
              roundCap: true,
              clip: false,
              itemStyle: {
                borderWidth: 1,
                borderColor: '#464646'
              }
            },
            axisLine: {
              lineStyle: {
                width: 40
              }
            },
            splitLine: {
              show: false,
              distance: 0,
              length: 10
            },
            axisTick: {
              show: false
            },
            axisLabel: {
              show: false,
              distance: 50
            },
            data: this.gaugeData,
            title: {
              fontSize: 14
            },
            detail: {
              width: 50,
              height: 14,
              fontSize: 14,
              color: 'inherit',
              borderColor: 'inherit',
              borderRadius: 20,
              borderWidth: 1,
              formatter: '{value}'
            }
          }
        ]
      })
    },
    // 绘制结果柱状图
    drawResultEcharts() {
      let resultEcharts = echarts.init(document.querySelector('.result-echarts'));
      resultEcharts.setOption({
        tooltip: {
          trigger: 'axis',
          axisPointer: { // 坐标轴指示器，坐标轴触发有效
            type: 'shadow' // 默认为直线，可选为：'line' | 'shadow'
          }
        },
        grid: {
          top: '10%',
          left: '2%',
          right: '2%',
          containLabel: true
        },
        xAxis: [{
          type: 'category',
          data: this.diseaseBarDataX,
          axisTick: {
            alignWithLabel: true
          },
          axisLabel: {
            interval: 0,
            rotate: 40
          }
        }],
        yAxis: [{
          type: 'value',
          axisTick: {
            show: false
          },
          axisLabel: {
            show: false, // 不显示坐标轴上的文字
          },
        }],
        series: [{
          name: '是否患病（值为1及患病）',
          type: 'bar',
          stack: 'vistors',
          label: {
            show: true, //开启显示
            position: 'top', //在上方显示
            formatter: function (params) {
              // params.value 是当前柱状图的数据值
              return params.value === 1 ? '确诊' : '未确诊';
            },
            textStyle: { //数值样式
              color: 'black',//字体颜色
              fontSize: 10//字体大小
            }
          },
          barWidth: '60%',
          data: this.probData,
          //给柱状图整体设置颜色
          itemStyle: {
            normal: {
              color: '#4ad2ff'
            },
          },
          animationDuration
        }]
      })
    },
    // 下载用于自助诊断的pdf模板
    downloadPdfTemplate() {
      // 创建一个隐藏的<a>元素
      let link = document.createElement('a');
      link.style.display = 'none';
      document.body.appendChild(link);

      // 通过 Flask 的路由来获取文件路径
      link.href = 'https://yiyuy.mynatapp.cc/data/downloadPdfTemplate';
      link.download = 'pdfTemplate.pdf';

      // 模拟点击事件来触发文件下载
      link.click();

      // 移除创建的<a>元素
      document.body.removeChild(link);
    },
    // 一键导出诊断报告
    async exportDiagnosisResult() {
      try {
        // 1. 加载模板文件
        const response = await fetch("/template.docx");	// 这里是去路径下拿模板了
        const templateData = await response.arrayBuffer();
        // 2. 初始化 PizZip 和 Docxtemplater
        const zip = new PizZip(templateData);

        // 通过base64将图片插入word
        const leftImageArrayBuffer = this.base64DataURLToArrayBuffer(this.leftBase64);
        const rightImageArrayBuffer = this.base64DataURLToArrayBuffer(this.rightBase64);
        const imgDataDict = {
          leftFundus: leftImageArrayBuffer,
          rightFundus: rightImageArrayBuffer
        };

        const doc = new Docxtemplater(zip, {
          paragraphLoop: true,
          linebreaks: true,
          modules: [
            new ImageModule({
              getImage: (value, key) => {
                return imgDataDict[key];
              },
              getSize: (afterValue, value, key) => {
                return [200, 200];
              },
            }),
          ],
        });

        // 构造识别结果和治疗建议
        let result = '', suggestion = '';
        if (this.probData[0] === 1) {
          result = '正常';
          suggestion = '您的眼底很健康，请继续爱护您的眼底。'
        } else {
          for (let i = 0; i < this.probData.length; i++) {
            if (this.probData[i] === 1) {
              result += this.idxToDisease[i] + ",";
              if (this.nowUser.role === 0 || this.nowUser.role === 2) {
                suggestion += this.idxToAdviceWithoutHTML[i] + "\n";
              } else {
                suggestion += this.idxToAdviceDoctorWithoutHTML[i] + "\n";
              }

            }
          }
        }

        let gender = '';
        if (this.infoForm.gender !== '') {
          gender = this.infoForm.gender === 'Female' ? '女' : '男';
        }

        // 3. 设置模板数据，并传入模板实例
        const data = {
          username: this.nowUser.username,
          gender: gender,
          age: this.infoForm.age,
          createTime: new Date(),
          leftFundus: "leftFundus",
          rightFundus: "rightFundus",
          result: result,
          suggestion: suggestion
        };
        doc.setData(data);

        // 4. 渲染文档
        doc.render();

        // 5. 生成 Word 文件
        const out = doc.getZip().generate({type: 'blob'});
        saveAs(out, '眼底疾病识别诊断结果.docx'); // 保存文件，文件名为 output.docx（可自行加工）
        this.$message.success('导出诊断报告成功')
      } catch (error) {
        console.log(error)
        this.$message.error('导出诊断报告失败')
      }
    },
    // 一键导出pdf版本诊断结果
    async exportPDFDiagnosisResult() {
      try {
        // 生成文字版结果和诊断建议
        // 如果是正常
        if (this.probData[0] === 1) {
          this.textResult = '正常'
          this.textSuggestion = '您的眼底很健康，请继续爱护您的眼底。'
        } else {
          for (let i = 0; i < this.probData.length; i++) {
            if (this.probData[i] === 1) {
              this.textResult += this.idxToDisease[i] + ",";
              if (this.nowUser.role === 0 || this.nowUser.role === 2) {
                this.textSuggestion += this.idxToAdvice[i] + "\n";
              } else {
                this.textSuggestion += this.idxToAdviceDoctor[i] + "\n";
              }
            }
          }
        }
        this.$refs.html2Pdf.generatePdf()
        this.$message.success('生成pdf诊断报告成功')
      } catch (error) {
        console.log(error)
        this.$message.error('生成pdf诊断报告失败')
      }
    },
    // 点击同意采集信息后触发的函数
    agreeGatherInformation() {
      this.innerGatherInformation = true;
      this.infoForm = {
        age: '',
        gender: '',
        description: '',
        result: ''
      }
    },
    showDetailInfo(item) {
      this.innerSimilarCase = true;
      this.similarCase = item
    },
    clickShowSolution() {
      this.showSolutionDialog = true;
      this.suggestionList = []
      // 构造suggestionList数组
      for (let i = 0; i < this.probData.length; i++) {
        let obj = {
          disease: '',
          reason: '',
          advice: '',
          similarList: [],
        }
        if (i !== 0 && this.probData[i] === 1) {
          obj.disease = this.idxToDisease[i]
          obj.reason = this.idxToReason[i]
          if (this.nowUser.role === 0 || this.nowUser.role === 2) {
            obj.advice = this.idxToAdvice[i]
          } else {
            obj.advice = this.idxToAdviceDoctor[i]
          }
          getTopKCase(i, 3).then(res => {
            obj.similarList = res.data;
            this.suggestionList.push(obj)
          })
        }
      }
    },
    submitInfoForm() {
      if (this.infoForm.age === '') {
        this.$message.warning('请输入年龄')
        return;
      }

      if (this.infoForm.gender === '') {
        this.$message.warning('请选择性别')
        return;
      }

      if (this.infoForm.description === '') {
        this.$message.warning('请输入患病期间症状')
      }

      this.gatherInformation = false;
      this.innerGatherInformation = false;

      let result = ''
      for (let i = 0; i < this.probData.length; i++) {
        if (this.probData[i] === 1) {
          result += i + ','
        }
      }
      this.infoForm.result = result
      this.infoForm.username = this.nowUser.username

      // 将左右眼底图像上传到oss
      let formData = new FormData()
      formData.append("files", this.leftFile)
      formData.append("files", this.rightFile)
      // 上传左右眼文件到oss
      axios.post('https://yiyuy.mynatapp.cc/info/batchImageToOSS', formData, {
        headers: {"Content-Type": "multipart/form-data"}
      }).then(response => {
        this.infoForm.leftFundus = response.data.data[0];
        this.infoForm.rightFundus = response.data.data[1];
        submitInfo(this.infoForm).then(res => {
          this.$message.success('信息上传成功，您的信息将会帮助更多人!')
        })
      }).catch(error => {
        console.log(error)
        this.$message.error("信息上传失败！");
      });
    },
    showAllResult() {
      this.showAllProb = true
      this.$nextTick(() => {
        this.drawRiskScoreEcharts();
      })
    },
    // 前端保存增强后的图片 传入sign 为0代表左眼 为1代表右眼
    saveEnhanceImg(sign) {
      if (this.leftEnhanceImg === '' || this.rightEnhanceImg === '') {
        this.$message.error('请先上传图片进行图片增强')
        return
      }
      let base64Src;
      let filename;
      if (sign === 0) {
        base64Src = this.leftEnhanceImg
        filename = 'left_enhance_img.jpg'
      } else {
        base64Src = this.rightEnhanceImg
        filename = 'right_enhance_img.jpg'
      }
      var base64 = base64Src.toString(); // imgSrc 就是base64哈
      var byteCharacters = atob(
          base64.replace(/^data:image\/(png|jpeg|jpg);base64,/, "")
      );
      var byteNumbers = new Array(byteCharacters.length);
      for (var i = 0; i < byteCharacters.length; i++) {
        byteNumbers[i] = byteCharacters.charCodeAt(i);
      }
      var byteArray = new Uint8Array(byteNumbers);
      var blob = new Blob([byteArray], {
        type: undefined,
      });
      var aLink = document.createElement("a");
      aLink.download = filename; //这里写保存时的图片名称
      aLink.href = URL.createObjectURL(blob);
      aLink.click();
    },
    // 点击开始识别按钮
    startDiagnosis() {
      // 卫语句
      if (this.form.leftFilename === '' || this.form.rightFilename === '') {
        this.$message.error('请先上传图片')
        return;
      }

      // 做一个过度
      let loadingText = 'LLAVA正在生成图片描述...'
      // 0.开启整页加载
      this.loading = this.$loading({
        lock: true,
        text: loadingText,
        spinner: 'el-icon-loading',
        background: 'rgba(0, 0, 0, 0.7)'
      });

      // 1.右箭头隐藏
      var rightArrows = document.querySelectorAll('.arrow-img');
      for (let i = 0; i < rightArrows.length; i++) {
        rightArrows[i].style.opacity = 0
      }

      // 2.预处理框隐藏
      var picEnhances = document.querySelectorAll('.pic-enhance');
      for (let i = 0; i < picEnhances.length; i++) {
        picEnhances[i].style.opacity = 0;
      }

      // 3.合并箭头隐藏
      var mergeArrow = document.querySelector('.merge-arrow');
      mergeArrow.style.opacity = 0;

      // 4.虚线隐藏
      var line = document.querySelector('.divider')
      line.style.opacity = 0;

      // 5.热力图隐藏
      var gradCam = document.querySelector('.gram-cam');
      gradCam.style.opacity = 0;

      // 6.患病概率隐藏
      var probTable = document.querySelector('.probability-list');
      probTable.style.opacity = 0;

      // 恢复右箭头
      setTimeout(() => {
        for (let i = 0; i < rightArrows.length; i++) {
          rightArrows[i].style.opacity = 1;
        }
      }, 100)

      // 修改step
      this.step = 3;

      axios.post('/llava/getImageDescription', this.form).then(res => {
        this.form.description = res.data.data

        // 修改加载文本
        loadingText = '亮度增强网络正在努力工作...'
        this.loading.setText(loadingText)

        // 1.进行图片增强 并返回结果
        enhanceImage(this.form).then(res => {
          this.leftEnhanceImg = 'data:image/png;base64,' + res.data['leftEnhanceImage']
          this.rightEnhanceImg = 'data:image/png;base64,' + res.data['rightEnhanceImage']

          // 修改加载文本
          loadingText = '热力图生成网络正在努力工作...'
          this.loading.setText(loadingText)

          // 恢复处理框
          setTimeout(() => {
            for (let i = 0; i < picEnhances.length; i++) {
              picEnhances[i].style.opacity = 1;
            }
          }, 100)

          // 过200ms后恢复合并箭头
          setTimeout(() => {
            mergeArrow.style.opacity = 1;
          }, 200)

          // 过300s后恢复分割线
          setTimeout(() => {
            line.style.opacity = 1;
          }, 300)

          // 2.单模态模型制作热力图，并返回结果
          makeGradCam(this.form).then(result => {
            this.leftGradCam = 'data:image/png;base64,' + result.data['leftGradCam']
            this.rightGradCam = 'data:image/png;base64,' + result.data['rightGradCam']

            // 恢复热力图
            gradCam.style.opacity = 1;

            // 修改加载文本
            loadingText = '多模态网络正在努力预测...'
            this.loading.setText(loadingText)

            // 3.多模态模型获得疾病概率，并返回结果
            getProbList(this.form).then(finalResult => {
              // 反馈
              this.$message.success('模型诊断成功')

              // 恢复概率表
              probTable.style.opacity = 1;

              // 显示导出诊断表格按钮
              this.showExportButton = true;

              // 关闭全局加载
              this.loading.close()

              // 寻问大模型要用的中文识别结果
              let chnResult = ''

              // 设定的阈值
              let threshold = 0.8
              this.probData = []
              this.allProbTable = []
              let sum = 0;
              for (let i = 0; i < finalResult.data.length; i++) {
                if (finalResult.data[i].prob > threshold) {
                  // 大于阈值 预测结果为1 同时获取中文识别结果，用于寻问大模型
                  this.probData.push(1)
                  sum++;
                  chnResult += this.idxToDisease[i] + ','
                } else {
                  this.probData.push(0)
                }

                // 不管预测结果有没有比阈值大 都加到全部结果的TABLE中
                this.allProbTable.push({
                  abbreviation: finalResult.data[i].abbreviation,
                  disease: finalResult.data[i].disease,
                  prob: finalResult.data[i].prob
                })
              }
              this.drawResultEcharts()

              let that = this;

              // 空闲2秒后 弹出询问框
              if (sum === 1 && this.probData[0] === 1) {
                // 用户是健康的 不需要采集信息
              } else {
                setTimeout(() => {
                  that.gatherInformation = true;
                }, 2000)
              }

              // 获取大模型对并疾病风险评分及疾病等级分类
              let question = `这是两张眼底图像，深度学习识别结果为${chnResult}给出我疾病风险评分，范围在0~100，同时给出疾病严重分级，共六个值，分别是0-代表患病无风险，20-代表患病程度轻，40-代表患病程度较轻，60-代表患病程度较重，80-代表患病程度重，100-代表患病程度严重。疾病风险评分与疾病严重分级用逗号分割，比如75,20这种格式，记住你只需要回答我的问题，不需要说其他话。`
              this.socket.emit('startTalk', {
                question: question,
                leftFilename: this.form.leftFilename,
                rightFilename: this.form.rightFilename
              })

              // 重置表单
              this.form = {
                leftFilename: '',
                rightFilename: '',
                description: '',
              }

              this.$refs.leftFundusUpload.clearFiles()
              this.$refs.rightFundusUpload.clearFiles()

              this.step = 4
            })
          })
        })
      })

    },
    base64DataURLToArrayBuffer(dataURL) {
      const base64Regex = /^data:image\/(png|jpg|jpeg|svg|svg\+xml);base64,/;
      if (!base64Regex.test(dataURL)) {
        return false;
      }
      const stringBase64 = dataURL.replace(base64Regex, "");
      let binaryString;
      if (typeof window !== "undefined") {
        binaryString = window.atob(stringBase64);
      } else {
        binaryString = new Buffer(stringBase64, "base64").toString("binary");
      }
      const len = binaryString.length;
      const bytes = new Uint8Array(len);
      for (let i = 0; i < len; i++) {
        const ascii = binaryString.charCodeAt(i);
        bytes[i] = ascii;
      }
      return bytes.buffer;
    }
  },
  watch: {},
}
</script>

<style lang="less" scoped>
@keyframes MoveIn {
  0% {
    opacity: 0;
    transform: translateY(12px);
  }

  100% {
    opacity: 1;
    transform: translateY(0);
  }
}

.container {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  animation: MoveIn .7s cubic-bezier(.4, 0, .2, 1);
  padding-top: 10px;

  .main-box {
    width: 100%;
    flex: 1;
    padding-left: 5px;
    padding-right: 5px;

    .upper-area {
      height: 80%;
      width: 100%;
      display: flex;

      .image-area {
        height: 100%;
        width: 55%;

        .left-upload, .right-upload {
          width: 100%;
          height: 50%;
          display: flex;
          align-items: center;

          .pic-upload {
            width: 47.5%;
            height: 80%;
            display: flex;
            flex-direction: column;
            justify-content: center;
            position: relative;

            /deep/ .el-upload {
              width: 100%;
            }

            /deep/ .el-upload .el-upload-dragger {
              width: 100%;
            }

            /deep/ .el-upload__tip {
              display: flex;
              flex-direction: column;
            }

            .keywords-select {
              width: 100%;

              .keywords-icon {
                font-size: 18px;
                margin-left: 2px;
              }
            }
          }

          .arrow-img {
            width: 5%;
            height: 12%;
            margin-left: 1%;
            margin-right: 1%;

            opacity: 1;
            transition: all 0.5s;
          }

          .pic-enhance {
            width: 47.5%;
            height: 70%;
            display: flex;
            flex-direction: column;
            justify-content: center;

            opacity: 1;
            transition: all 0.5s;


            .enhance-pic-inner {
              width: 100%;
              height: 100%;
              border: 1px dashed #ccc;

              .without-img {
                width: 100%;
                height: 100%;
                display: flex;
                flex-direction: column;
                align-items: center;
                justify-content: center;

                .enhance-icon {
                  width: 60px;
                  height: 60px;
                }

                .enhance-tip {
                  margin-top: 2%;
                  font-size: 14px;
                  color: #606266;
                }
              }

              .with-img {
                width: 100%;
                height: 100%;
              }
            }
          }

          .enhance-download-btn {
            width: 100%;
            display: flex;
            align-items: center;
            justify-content: center;
            margin-top: 8px;
          }
        }
      }

      .result-area {
        flex: 1;
        height: 100%;
        display: flex;
        align-items: center;

        .merge-arrow {
          width: 10%;
          height: 10%;

          opacity: 1;
          transition: all 0.5s;
        }

        .result-info {
          height: 100%;
          flex: 1;

          .gram-cam {
            width: 100%;
            height: 47.5%;
            display: flex;
            flex-direction: column;

            opacity: 1;
            transition: all 0.5s;

            .grad-cam-blank {
              height: 45%;
            }

            .grad-cam-img {
              width: 100%;
              flex: 1;
              display: flex;

              .left-grad-cam, .right-grad-cam {
                width: 50%;
                border: 1px dashed #ccc;
                height: 100%;

                .without-grad-img {
                  width: 100%;
                  height: 100%;
                  display: flex;
                  flex-direction: column;
                  align-items: center;
                  justify-content: center;

                  .grad-cam-icon {
                    width: 65px;
                    height: 65px;
                  }

                  .grad-cam-tip {
                    margin-top: 2%;
                    font-size: 14px;
                    color: #606266;
                  }
                }

                .with-grad-img {
                  width: 100%;
                  height: 100%;
                }
              }
            }

          }

          .divider {
            height: 5%;
            display: flex;
            align-items: center;

            opacity: 1;
            transition: all 0.5s;
          }

          .probability-list {
            height: 47.5%;
            opacity: 1;
            transition: all 0.5s;
            display: flex;
            flex-direction: column;
            padding-right: 10px;

            .result-echarts {
              width: 100%;
              flex: 1;
            }
          }
        }
      }
    }

    .submit-group {
      width: 100%;
      display: flex;
      flex-direction: column;
      align-items: center;

      .submit-btn {
        width: 100%;
        display: flex;
        align-items: center;
        justify-content: center;;
      }

      .auto-diagnosis-tip {
        margin-top: 5px;
        width: 100%;
        font-size: 13px;
        display: flex;
        align-items: center;
        justify-content: center;
        color: #909399;

        .click-me {
          color: #409EFF;
          cursor: pointer;
        }

        .click-me:hover {
          text-decoration: underline;
        }

        .download-template {
          color: #409EFF;
          cursor: pointer;
        }

        .download-template:hover {
          text-decoration: underline;
        }
      }
    }

    .drawer-box {
      width: 100%;
      height: 100%;
      display: flex;
      flex-direction: column;

      .risk-score-echarts {
        width: 100%;
        flex: 1;
      }
    }
  }
}

.text-tip {
  display: flex;
  align-items: center;
  position: relative;

  .tip-icon {
    width: 30px;
    height: 30px;
  }

  .tip-text {
    font-size: 14px;
    font-weight: bold;
  }

  .showSolution {
    position: absolute;
    right: 0;
  }
}

.outer-text {
  font-size: 14px;
  font-weight: bold;
  color: #606266;
}

.wrapper {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;

  .header {
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    margin-top: 20px;

    .header-title {
      font-size: 28px;
      font-weight: 700;
    }
  }

  .blank {
    height: 2%;
  }

  .main {
    width: 40%;
    margin: 0 auto;

    .fundus-image {
      display: flex;
    }
  }
}
</style>